home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrecord-1.8.1 / lib / format.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-31  |  15.2 KB  |  725 lines

  1. /* @(#)format.c    1.29 98/03/31 Copyright 1985 J. Schilling */
  2. /*
  3.  *    format
  4.  *    common code for printf fprintf & sprintf
  5.  *
  6.  *    allows recursive printf with "%r", used in:
  7.  *    error, comerr, comerrno, errmsg, errmsgno and the like
  8.  *
  9.  *    Copyright (c) 1985 J. Schilling
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; see the file COPYING.  If not, write to
  24.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. #include <mconfig.h>
  28. #include <vadefs.h>
  29. #include <strdefs.h>
  30. #include <stdxlib.h>
  31. #ifndef    HAVE_STDLIB_H
  32. extern    char    *gcvt __PR((double, int, char *));
  33. #endif
  34. #include <standard.h>
  35.  
  36. /*
  37.  * Some CPU's (e.g. PDP-11) cannot do logical shifts.
  38.  * They use rotate instead. Masking the low bits before,
  39.  * makes rotate work too.
  40.  */
  41. #define    allmask(t)    ((unsigned t)~((unsigned t)0))
  42. #define    lowmask(t, x)    ((unsigned t)~((unsigned t)((1 << (x))-1) ))
  43. #define    rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))
  44.  
  45. #define    CHARMASK    makemask(char)
  46. #define    SHORTMASK    makemask(short)
  47. #define    INTMASK        makemask(int)
  48. #define    LONGMASK    makemask(long)
  49.  
  50. #ifdef    DIVLBYS
  51. extern    long    divlbys();
  52. extern    long    modlbys();
  53. #else
  54. #define    divlbys(val, base)    ((val)/(base))
  55. #define    modlbys(val, base)    ((val)%(base))
  56. #endif
  57.  
  58. /*
  59.  *    We use macros here to avoid the need to link to the international
  60.  *    character routines.
  61.  *    We don't need internationalization for our purpose.
  62.  */
  63. #define    is_dig(c)    (((c) >= '0') && ((c) <= '9'))
  64. #define    is_cap(c)    ((c) >= 'A' && (c) <= 'Z')
  65. #define    to_cap(c)    (is_cap(c) ? c : c - 'a' + 'A')
  66. #define    cap_ty(c)    (is_cap(c) ? 'L' : 'I')
  67.  
  68. typedef unsigned int    Uint;
  69. typedef unsigned short    Ushort;
  70. typedef unsigned long    Ulong;
  71. #ifdef    HAVE_LONGLONG
  72. typedef unsigned long long    Ullong;
  73. #endif
  74.  
  75. typedef struct f_args {
  76.     void    (*outf) __PR((char, long)); /* Func from format(fun, arg) */
  77.     long    farg;                /* Arg from format (fun, arg) */
  78.     int    minusflag;
  79.     int    flags;
  80.     int    fldwidth;
  81.     int    signific;
  82.     int    lzero;
  83.     char    *buf;
  84.     char    *bufp;
  85.     char    fillc;
  86.     char    *prefix;
  87.     int    prefixlen;
  88. } f_args;
  89.  
  90. #define    MINUSFLG    1    /* '-' flag */
  91. #define    PLUSFLG        2    /* '+' flag */
  92. #define    SPACEFLG    4    /* ' ' flag */
  93. #define    HASHFLG        8    /* '#' flag */
  94.  
  95. LOCAL    void    prnum  __PR((Ulong, unsigned, f_args *));
  96. LOCAL    void    prdnum __PR((Ulong, f_args *));
  97. LOCAL    void    pronum __PR((Ulong, f_args *));
  98. LOCAL    void    prxnum __PR((Ulong, f_args *));
  99. LOCAL    void    prXnum __PR((Ulong, f_args *));
  100. LOCAL    int    prbuf  __PR((const char *, f_args *));
  101. LOCAL    int    prc    __PR((char, f_args *));
  102. LOCAL    int    prstring __PR((const char *, f_args *));
  103.  
  104.  
  105. #ifdef    PROTOTYPES
  106. EXPORT int format(    void (*fun)(char, long),
  107.             long farg,
  108.             const char *fmt,
  109.             va_list args)
  110. #else
  111. EXPORT int format(fun, farg, fmt, args)
  112.     register void    (*fun)();
  113.     register long    farg;
  114.     register char    *fmt;
  115.     va_list        args;
  116. #endif
  117. {
  118.     char buf[512];
  119.     const char *sfmt;
  120.     register int unsflag;
  121.     register long val;
  122.     register char type;
  123.     register char mode;
  124.     register char c;
  125.     int count;
  126.     int i;
  127.     short sh;
  128.     const char *str;
  129.     double dval;
  130.     Ulong res;
  131.     char *rfmt;
  132.     f_args    fa;
  133.  
  134.     fa.outf = fun;
  135.     fa.farg = farg;
  136.     count = 0;
  137.     /*
  138.      * Main loop over the format string.
  139.      * Increment and check for end of string is made here.
  140.      */
  141.     for(; *fmt != '\0'; fmt++) {
  142.         c = *fmt;
  143.         while (c != '%') {
  144.             if (c == '\0')
  145.                 return (count);
  146.             (*fun)(c, farg);
  147.             c = *(++fmt);
  148.             count++;
  149.         }
  150.  
  151.         /*
  152.          * We reached a '%' sign.
  153.          */
  154.         buf[0] = '\0';
  155.         fa.buf = fa.bufp = buf;
  156.         fa.minusflag = 0;
  157.         fa.flags = 0;
  158.         fa.fldwidth = 0;
  159.         fa.signific = -1;
  160.         fa.lzero = 0;
  161.         fa.fillc = ' ';
  162.         fa.prefixlen = 0;
  163.         sfmt = fmt;
  164.         unsflag = FALSE;
  165.     newflag:
  166.         switch (*(++fmt)) {
  167.  
  168.         case '+':
  169.             fa.flags |= PLUSFLG;
  170.             goto newflag;
  171.  
  172.         case '-':
  173.             fa.minusflag++;
  174.             goto newflag;
  175.  
  176.         case ' ':
  177.             /*
  178.              * If the space and the + flag are present,
  179.              * the space flag will be ignored.
  180.              */
  181.             fa.flags |= SPACEFLG;
  182.             goto newflag;
  183.  
  184.         case '#':
  185.             fa.flags |= HASHFLG;
  186.             goto newflag;
  187.  
  188.         case '0':
  189.             /*
  190.              * '0' is a flag.
  191.              */
  192.             fa.fillc = '0';
  193.             goto newflag;
  194.         }
  195.         if (*fmt == '*') {
  196.             fmt++;
  197.             fa.fldwidth = va_arg(args, int);
  198.             /*
  199.              * A negative fieldwith is a minus flag with a
  200.              * positive fieldwidth.
  201.              */
  202.             if (fa.fldwidth < 0) {
  203.                 fa.fldwidth = -fa.fldwidth;
  204. /*                fa.minusflag ^= 1;*/
  205.                 fa.minusflag = 1;
  206.             }
  207.         } else while (c = *fmt, is_dig(c)) {
  208.             fa.fldwidth *= 10;
  209.             fa.fldwidth += c - '0';
  210.             fmt++;
  211.         }
  212.         if (*fmt == '.') {
  213.             fmt++;
  214.             fa.signific = 0;
  215.             if (*fmt == '*') {
  216.                 fmt++;
  217.                 fa.signific = va_arg(args, int);
  218.                 if (fa.signific < 0)
  219.                     fa.signific = 0;
  220.             } else while (c = *fmt, is_dig(c)) {
  221.                 fa.signific *= 10;
  222.                 fa.signific += c - '0';
  223.                 fmt++;
  224.             }
  225.         }
  226.         if (strchr("UCSIL", *fmt)) {
  227.             /*
  228.              * Enhancements to K&R and ANSI:
  229.              *
  230.              * got a type specifyer
  231.              */
  232.             if (*fmt == 'U') {
  233.                 fmt++;
  234.                 unsflag = TRUE;
  235.             }
  236.             if (!strchr("CSILZODX", *fmt)) {
  237.                 /*
  238.                  * Got only 'U'nsigned specifyer,
  239.                  * use default type and mode.
  240.                  */
  241.                 type = 'I';
  242.                 mode = 'D';
  243.                 fmt--;
  244.             } else if (!strchr("CSIL", *fmt)) {
  245.                 /*
  246.                  * no type, use default
  247.                  */
  248.                 type = 'I';
  249.                 mode = *fmt;
  250.             } else {
  251.                 /*
  252.                  * got CSIL
  253.                  */
  254.                 type = *fmt++;
  255.                 if (!strchr("ZODX", mode = *fmt)) {
  256.                     fmt--;
  257.                     mode = 'D';/* default mode */
  258.                 }
  259.             }
  260.         } else switch(*fmt) {
  261.  
  262.         case 'h':
  263.             type = 'S';        /* convert to type */
  264.             goto getmode;
  265.  
  266.         case 'l':
  267.             type = 'L';        /* convert to type */
  268.  
  269.         getmode:
  270.             if (!strchr("udioxX", *(++fmt))) {
  271.                 fmt--;
  272.                 mode = 'D';
  273.             } else {
  274.                 mode = *fmt;
  275.                 if (mode != 'x')
  276.                     mode = to_cap(mode);
  277.                 if (mode == 'U')
  278.                     unsflag = TRUE;
  279.                 else if (mode == 'I')    /*XXX */
  280.                     mode = 'D';
  281.             }
  282.             break;
  283.         case 'x':
  284.             mode = 'x';
  285.             goto havemode;
  286.         case 'u':
  287.             unsflag = TRUE;
  288.         case 'o': case 'O':
  289.         case 'd': case 'D':
  290.         case 'i': case 'I':
  291.         case 'p':
  292.         case 'X':
  293.         case 'z': case 'Z':
  294.             mode = to_cap(*fmt);
  295.         havemode:
  296.             type = cap_ty(*fmt);
  297.             if (mode == 'I')    /*XXX kann entfallen*/
  298.                 mode = 'D';    /*wenn besseres uflg*/
  299.             break;
  300.  
  301.         case '%':
  302.             count += prc('%', &fa);
  303.             continue;
  304.         case ' ':
  305.             count += prbuf("", &fa);
  306.             continue;
  307.         case 'c':
  308.             c = va_arg(args, int);
  309.             count += prc(c, &fa);
  310.             continue;
  311.         case 's':
  312.             str = va_arg(args, char *);
  313.             count += prstring(str, &fa);
  314.             continue;
  315.         case 'b':
  316.             str = va_arg(args, char *);
  317.             fa.signific = va_arg(args, int);
  318.             count += prstring(str, &fa);
  319.             continue;
  320.  
  321. #ifndef    NO_FLOATINGPOINT
  322.         case 'e':
  323.             if (fa.signific == -1)
  324.                 fa.signific = 6;
  325.             dval = va_arg(args, double);
  326.             ftoes(buf, dval, 0, fa.signific);
  327.             count += prbuf(buf, &fa);
  328.             continue;
  329.         case 'f':
  330.             if (fa.signific == -1)
  331.                 fa.signific = 6;
  332.             dval = va_arg(args, double);
  333.             ftofs(buf, dval, 0, fa.signific);
  334.             count += prbuf(buf, &fa);
  335.             continue;
  336.         case 'g':
  337.             if (fa.signific == -1)
  338.                 fa.signific = 6;
  339.             if (fa.signific == 0)
  340.                 fa.signific = 1;
  341.             dval = va_arg(args, double);
  342.             gcvt(dval, fa.signific, buf);
  343.             count += prbuf(buf, &fa);
  344.             continue;
  345. #else
  346. #    ifdef    USE_FLOATINGARGS
  347.         case 'e':
  348.         case 'f':
  349.         case 'g':
  350.             dval = va_arg(args, double);
  351.             continue;
  352. #    endif
  353. #endif
  354.  
  355.         case 'r':            /* recursive printf */
  356.         case 'R':            /* recursive printf */
  357.             rfmt  = va_arg(args, char *);
  358.             /*
  359.              * I don't know any portable way to get an arbitrary
  360.              * C object from a var arg list so I use a
  361.              * system-specific routine __va_arg_list() that knows
  362.              * if 'va_list' is an array. You will not be able to
  363.              * assign the value of __va_arg_list() but it works
  364.              * to be used as an argument of a function.
  365.              * It is a requirement for recursive printf to be able
  366.              * to use this function argument. If your system
  367.              * defines va_list to be an array you need to know this
  368.              * via autoconf or another mechanism.
  369.              * It would be nice to have something like
  370.              * __va_arg_list() in stdarg.h
  371.              */
  372.             count += format(fun, farg, rfmt, __va_arg_list(args));
  373.             continue;
  374.  
  375.         case 'n':
  376.             {
  377.                 int    *ip = va_arg(args, int *);
  378.  
  379.                 *ip = count;
  380.             }
  381.             continue;
  382.  
  383.         default:            /* Unknown '%' format */
  384.             sfmt++;            /* Dont't print '%'   */
  385.             count += fmt - sfmt;
  386.             while (sfmt < fmt)
  387.                 (*fun)(*(sfmt++), farg);
  388.             if (*fmt == '\0') {
  389.                 fmt--;
  390.                 continue;
  391.             } else {
  392.                 (*fun)(*fmt, farg);
  393.                 count++;
  394.                 continue;
  395.             }
  396.         }
  397.         /*
  398.          * print numbers:
  399.          * first prepare type 'C'har, 'S'hort, 'I'nt, or 'L'ong
  400.          */
  401.         switch(type) {
  402.  
  403.         case 'C':
  404.             c = va_arg(args, int);
  405.             val = c;        /* extend sign here */
  406.             if (unsflag || mode != 'D')
  407. #ifdef    DO_MASK
  408.                 val &= CHARMASK;
  409. #else
  410.                 val = (unsigned char)val;
  411. #endif
  412.             break;
  413.         case 'S':
  414.             sh = va_arg(args, int);
  415.             val = sh;        /* extend sign here */
  416.             if (unsflag || mode != 'D')
  417. #ifdef    DO_MASK
  418.                 val &= SHORTMASK;
  419. #else
  420.                 val = (unsigned short)val;
  421. #endif
  422.             break;
  423.         case 'I':
  424.         default:
  425.             i = va_arg(args, int);
  426.             val = i;        /* extend sign here */
  427.             if (unsflag || mode != 'D')
  428. #ifdef    DO_MASK
  429.                 val &= INTMASK;
  430. #else
  431.                 val = (unsigned int)val;
  432. #endif
  433.             break;
  434.         case 'P':
  435.         case 'L':
  436.             val = va_arg(args, long);
  437.             break;
  438.         }
  439.  
  440.         /*
  441.          * Final print out, take care of mode:
  442.          * mode is one of: 'O'ctal, 'D'ecimal, or he'X'
  443.          * oder 'Z'weierdarstellung.
  444.          */
  445.         fa.bufp = &buf[sizeof(buf)-1];
  446.         *--fa.bufp = '\0';
  447.  
  448.         if (val == 0 && mode != 'D') {
  449.         printzero:
  450.             /*
  451.              * Printing '0' with fieldwidth 0 results in no chars.
  452.              */
  453.             fa.lzero = -1;
  454.             if (fa.signific >= 0)
  455.                 fa.fillc = ' ';
  456.             count += prstring("0", &fa);
  457.             continue;
  458.         } else switch(mode) {
  459.  
  460.         case 'D':
  461.             if (!unsflag && val < 0) {
  462.                 fa.prefix = "-";
  463.                 fa.prefixlen = 1;
  464.                 val = -val;
  465.             } else if (fa.flags & PLUSFLG) {
  466.                 fa.prefix = "+";
  467.                 fa.prefixlen = 1;
  468.             } else if (fa.flags & SPACEFLG) {
  469.                 fa.prefix = " ";
  470.                 fa.prefixlen = 1;
  471.             }
  472.             if (val == 0)
  473.                 goto printzero;
  474.         case 'U':
  475.             /* output a long unsigned decimal number */
  476.             prdnum(val, &fa);
  477.             break;
  478.         case 'O':
  479.             /* output a long octal number */
  480.             if (fa.flags & HASHFLG) {
  481.                 fa.prefix = "0";
  482.                 fa.prefixlen = 1;
  483.             }
  484.             pronum(val & 07, &fa);
  485.             if ((res = (val>>3) & rshiftmask(long, 3)) != 0)
  486.                 pronum(res, &fa);
  487.             break;
  488.         case 'p':
  489.         case 'x':
  490.             /* output a hex long */
  491.             if (fa.flags & HASHFLG) {
  492.                 fa.prefix = "0x";
  493.                 fa.prefixlen = 2;
  494.             }
  495.             prxnum(val & 0xF, &fa);
  496.             if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  497.                 prxnum(res, &fa);
  498.             break;
  499.         case 'P':
  500.         case 'X':
  501.             /* output a hex long */
  502.             if (fa.flags & HASHFLG) {
  503.                 fa.prefix = "0X";
  504.                 fa.prefixlen = 2;
  505.             }
  506.             prXnum(val & 0xF, &fa);
  507.             if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  508.                 prXnum(res, &fa);
  509.             break;
  510.         case 'Z':
  511.             /* output a binary long */
  512.             prnum(val & 0x1, 2, &fa);
  513.             if ((res = (val>>1) & rshiftmask(long, 1)) != 0)
  514.                 prnum(res, 2, &fa);
  515.         }
  516.         fa.lzero = -1;
  517.         /*
  518.          * If a precision (fielwidth) is specified
  519.          * on diouXx conversions, the '0' flag is ignored.
  520.          */
  521.         if (fa.signific >= 0)
  522.             fa.fillc = ' ';
  523.         count += prbuf(fa.bufp, &fa);
  524.     }
  525.     return (count);
  526. }
  527.  
  528. /*
  529.  * Routines to print (not negative) numbers in an arbitrary base
  530.  */
  531. LOCAL    unsigned char    dtab[]  = "0123456789abcdef";
  532. LOCAL    unsigned char    udtab[] = "0123456789ABCDEF";
  533.  
  534. LOCAL void prnum(val, base, fa)
  535.     register Ulong val;
  536.     register unsigned base;
  537.     f_args *fa;
  538. {
  539.     register char *p = fa->bufp;
  540.  
  541.     do {
  542.         *--p = dtab[modlbys(val, base)];
  543.         val = divlbys(val, base);
  544.     } while (val > 0);
  545.  
  546.     fa->bufp = p;
  547. }
  548.  
  549. LOCAL void prdnum(val, fa)
  550.     register Ulong val;
  551.     f_args *fa;
  552. {
  553.     register char *p = fa->bufp;
  554.  
  555.     do {
  556.         *--p = dtab[modlbys(val, (unsigned)10)];
  557.         val = divlbys(val, (unsigned)10);
  558.     } while (val > 0);
  559.  
  560.     fa->bufp = p;
  561. }
  562.  
  563. /*
  564.  * We may need to use division here too (PDP-11, non two's complement ...)
  565.  */
  566. LOCAL void pronum(val, fa)
  567.     register Ulong val;
  568.     f_args *fa;
  569. {
  570.     register char *p = fa->bufp;
  571.  
  572.     do {
  573.         *--p = dtab[val & 7];
  574.         val >>= 3;
  575.     } while (val > 0);
  576.  
  577.     fa->bufp = p;
  578. }
  579.  
  580. LOCAL void prxnum(val, fa)
  581.     register Ulong val;
  582.     f_args *fa;
  583. {
  584.     register char *p = fa->bufp;
  585.  
  586.     do {
  587.         *--p = dtab[val & 15];
  588.         val >>= 4;
  589.     } while (val > 0);
  590.  
  591.     fa->bufp = p;
  592. }
  593.  
  594. LOCAL void prXnum(val, fa)
  595.     register Ulong val;
  596.     f_args *fa;
  597. {
  598.     register char *p = fa->bufp;
  599.  
  600.     do {
  601.         *--p = udtab[val & 15];
  602.         val >>= 4;
  603.     } while (val > 0);
  604.  
  605.     fa->bufp = p;
  606. }
  607.  
  608. /*
  609.  * Final buffer print out routine.
  610.  */
  611. LOCAL int prbuf(s, fa)
  612.     register const char *s;
  613.     f_args *fa;
  614. {
  615.     register int diff;
  616.     register int rfillc;
  617.     register long arg            = fa->farg;
  618.     register void (*fun) __PR((char, long))    = fa->outf;
  619.     register int count;
  620.     register int lzero = 0;
  621.  
  622.     count = strlen(s);
  623.  
  624.     if (fa->lzero < 0 && count < fa->signific)
  625.         lzero = fa->signific - count;
  626.     diff = fa->fldwidth - lzero - count - fa->prefixlen;
  627.     count += lzero;
  628.     if (diff > 0)
  629.         count += diff;
  630.  
  631.     if (fa->prefixlen && fa->fillc != ' ') {
  632.         while (*fa->prefix != '\0')
  633.             (*fun)(*fa->prefix++, arg);
  634.     }
  635.     if (!fa->minusflag) {
  636.         rfillc = fa->fillc;
  637.         while (--diff >= 0)
  638.             (*fun)(rfillc, arg);
  639.     }
  640.     if (fa->prefixlen && fa->fillc == ' ') {
  641.         while (*fa->prefix != '\0')
  642.             (*fun)(*fa->prefix++, arg);
  643.     }
  644.     if (lzero > 0) {
  645.         rfillc = '0';
  646.         while (--lzero >= 0)
  647.             (*fun)(rfillc, arg);
  648.     }
  649.     while (*s != '\0')
  650.         (*fun)(*s++, arg);
  651.     if (fa->minusflag) {
  652.         rfillc = ' ';
  653.         while (--diff >= 0)
  654.             (*fun)(rfillc, arg);
  655.     }
  656.     return (count);
  657. }
  658.  
  659. /*
  660.  * Print out one char, allowing prc('\0')
  661.  * Similar to prbuf()
  662.  */
  663. #ifdef    PROTOTYPES
  664.  
  665. LOCAL int prc(char c, f_args *fa)
  666.  
  667. #else
  668. LOCAL int prc(c, fa)
  669.     char    c;
  670.     f_args *fa;
  671. #endif
  672. {
  673.     register int diff;
  674.     register int rfillc;
  675.     register long arg            = fa->farg;
  676.     register void (*fun) __PR((char, long))    = fa->outf;
  677.     register int count;
  678.  
  679.     count = 1;
  680.     diff = fa->fldwidth - 1;
  681.     if (diff > 0)
  682.         count += diff;
  683.  
  684.     if (!fa->minusflag) {
  685.         rfillc = fa->fillc;
  686.         while (--diff >= 0)
  687.             (*fun)(rfillc, arg);
  688.     }
  689.     (*fun)(c, arg);
  690.     if (fa->minusflag) {
  691.         rfillc = ' ';
  692.         while (--diff >= 0)
  693.             (*fun)(rfillc, arg);
  694.     }
  695.     return (count);
  696. }
  697.  
  698. /*
  699.  * String output routine.
  700.  * If fa->signific is >= 0, it uses only fa->signific chars.
  701.  * If fa->signific is 0, print no characters.
  702.  */
  703. LOCAL int prstring(s, fa)
  704.     register const char    *s;
  705.     f_args *fa;
  706. {
  707.     register char    *bp;
  708.     register int    signific;
  709.  
  710.     if (s == NULL)
  711.         return (prbuf("(NULL POINTER)", fa));
  712.  
  713.     if (fa->signific < 0)
  714.         return (prbuf(s, fa));
  715.  
  716.     bp = fa->buf;
  717.     signific = fa->signific;
  718.  
  719.     while (--signific >= 0 && *s != '\0')
  720.         *bp++ = *s++;
  721.     *bp = '\0';
  722.  
  723.     return (prbuf(fa->buf, fa));
  724. }
  725.